﻿using System;
using System.Linq;
using System.Windows;
using System.Windows.Interop;
using System.Windows.Media;

namespace MT.Controls.Helper
{
    public static class VisualHelper
    {
        internal static VisualStateGroup TryGetVisualStateGroup(DependencyObject d, string groupName)
        {
            var root = GetImplementationRoot(d);
            if (root == null) return null;

            return VisualStateManager
                .GetVisualStateGroups(root)?
                .OfType<VisualStateGroup>()
                .FirstOrDefault(group => string.CompareOrdinal(groupName, group.Name) == 0);
        }

        internal static FrameworkElement GetImplementationRoot(DependencyObject d) =>
            1 == VisualTreeHelper.GetChildrenCount(d)
                ? VisualTreeHelper.GetChild(d, 0) as FrameworkElement
                : null;

        public static T GetChild<T>(DependencyObject d) where T : DependencyObject
        {
            if (d == null) return default;
            if (d is T t) return t;

            for (var i = 0; i < VisualTreeHelper.GetChildrenCount(d); i++)
            {
                var child = VisualTreeHelper.GetChild(d, i);
                var result = GetChild<T>(child);
                if (result != null) return result;
            }
            return default;
        }

        public static T GetParent<T>(DependencyObject d, Func<DependencyObject, bool> condition = null) where T : DependencyObject
        {
            if (d == null)
            {
                return default;
            }
            else if (d is T)
            {
                if (condition == null)
                    return (T)d;

                if (condition.Invoke(d))
                {
                    return (T)d;
                }
                else
                {
                    return GetParent<T>(VisualTreeHelper.GetParent(d), condition);
                }

            }
            else if (d is Window)
            {
                return null;
            }
            else
            {
                return GetParent<T>(VisualTreeHelper.GetParent(d), condition);
            }
        }

        public static IntPtr GetHandle(this Visual visual) => (PresentationSource.FromVisual(visual) as HwndSource)?.Handle ?? IntPtr.Zero;

        internal static void HitTestVisibleElements(Visual visual, HitTestResultCallback resultCallback, HitTestParameters parameters) =>
            VisualTreeHelper.HitTest(visual, ExcludeNonVisualElements, resultCallback, parameters);

        private static HitTestFilterBehavior ExcludeNonVisualElements(DependencyObject potentialHitTestTarget)
        {
            if (!(potentialHitTestTarget is Visual)) return HitTestFilterBehavior.ContinueSkipSelfAndChildren;

            if (!(potentialHitTestTarget is UIElement uIElement) || uIElement.IsVisible && uIElement.IsEnabled)
                return HitTestFilterBehavior.Continue;

            return HitTestFilterBehavior.ContinueSkipSelfAndChildren;
        }
    }
}
